#include "Bench.hpp"

#include <cstdarg>
namespace IntegralLib
{
	Benchmarker::Benchmarker() :
		OnReport([](void* UserData, double DurationSeconds){}) // 默认无任何输出
	{
	}

	void Benchmarker::Stop(bool DoReport)
	{
		if (!Stopped)
		{
			End = BenchTimer::now();
			Stopped = true;
		}
		if (DoReport) OnReport(UserData.get(), GetDurationS());
	}

	double Benchmarker::GetDurationS()
	{
		if (!Stopped) End = BenchTimer::now();
		return std::chrono::duration<double>(End - Start).count();
	}
	int64_t Benchmarker::GetDurationNS()
	{
		if (!Stopped) End = BenchTimer::now();
		return std::chrono::nanoseconds(End - Start).count();
	}
	int64_t Benchmarker::GetDurationUS()
	{
		if (!Stopped) End = BenchTimer::now();
		return std::chrono::duration_cast<std::chrono::microseconds>(End - Start).count();
	}
	int64_t Benchmarker::GetDurationMS()
	{
		if (!Stopped) End = BenchTimer::now();
		return std::chrono::duration_cast<std::chrono::milliseconds>(End - Start).count();
	}

	Benchmarker::~Benchmarker()
	{
		Stop(EnableReport);
	}

	Benchmarker::Benchmarker(bool DoReport, std::shared_ptr<void> UserData, void (*ReportFunc)(void* UserData, double DurationSeconds)) :
		EnableReport(DoReport),
		UserData(UserData),
		OnReport(ReportFunc)
	{
	}

	Benchmarker::Benchmarker(bool DoReport, const EasyReportData& UserData) :
		EnableReport(DoReport),
		UserData(std::make_shared<EasyReportData>(UserData)),
		OnReport([](void* UserData, double DurationSeconds){
			auto& d = *reinterpret_cast<EasyReportData*>(UserData);

			if (d.HowManyTimesUseDurationLF)
			{
				// 制造 snprintf 缓冲区
				constexpr int AvrSizeOfLg = 36;
				size_t PrintfBufSize = d.PrintfFormat.size() + 1 + size_t(d.HowManyTimesUseDurationLF) * AvrSizeOfLg;
				auto buf = std::make_unique<char[]>(PrintfBufSize);

				auto p = DurationSeconds * d.Multiply;

				switch (d.HowManyTimesUseDurationLF)
				{
#define PREFIX snprintf(buf.get(), PrintfBufSize, d.PrintfFormat.c_str()
#define SUBFIX ); break
#define P1  p
#define P2  P1,  p
#define P3  P2,  p
#define P4  P3,  p
#define P5  P4,  p
#define P6  P5,  p
#define P7  P6,  p
#define P8  P7,  p
#define P9  P8,  p
#define P10 P9,  p
#define P11 P10, p
#define P12 P11, p
#define P13 P12, p
#define P14 P13, p
#define P15 P14, p
#define P16 P15, p
#define P17 P16, p
#define P18 P17, p
#define P19 P18, p
#define P20 P19, p
#define P21 P20, p
#define P22 P21, p
#define P23 P22, p
#define P24 P23, p
#define P25 P24, p
#define P26 P25, p
#define P27 P26, p
#define P28 P27, p
#define P29 P28, p
#define P30 P29, p
#define P31 P30, p
#define P32 P31, p
			case 0:  PREFIX SUBFIX;
			case 1:  PREFIX, P1  SUBFIX;
			case 2:  PREFIX, P2  SUBFIX;
			case 3:  PREFIX, P3  SUBFIX;
			case 4:  PREFIX, P4  SUBFIX;
			case 5:  PREFIX, P5  SUBFIX;
			case 6:  PREFIX, P6  SUBFIX;
			case 7:  PREFIX, P7  SUBFIX;
			case 8:  PREFIX, P8  SUBFIX;
			case 9:  PREFIX, P9  SUBFIX;
			case 10: PREFIX, P10 SUBFIX;
			case 11: PREFIX, P11 SUBFIX;
			case 12: PREFIX, P12 SUBFIX;
			case 13: PREFIX, P13 SUBFIX;
			case 14: PREFIX, P14 SUBFIX;
			case 15: PREFIX, P15 SUBFIX;
			case 16: PREFIX, P16 SUBFIX;
			case 17: PREFIX, P17 SUBFIX;
			case 18: PREFIX, P18 SUBFIX;
			case 19: PREFIX, P19 SUBFIX;
			case 20: PREFIX, P20 SUBFIX;
			case 21: PREFIX, P21 SUBFIX;
			case 22: PREFIX, P22 SUBFIX;
			case 23: PREFIX, P23 SUBFIX;
			case 24: PREFIX, P24 SUBFIX;
			case 25: PREFIX, P25 SUBFIX;
			case 26: PREFIX, P26 SUBFIX;
			case 27: PREFIX, P27 SUBFIX;
			case 28: PREFIX, P28 SUBFIX;
			case 29: PREFIX, P29 SUBFIX;
			case 30: PREFIX, P30 SUBFIX;
			case 31: PREFIX, P31 SUBFIX;
			case 32: PREFIX, P32 SUBFIX;
			default:
				throw std::invalid_argument("You can only provide up to 32 arguments to `snprintf()` here.");
			};

				// 无论如何也要输出，谁叫你调用了这个函数
				if (d.LogTo) (*d.LogTo) << buf;
				else std::cout << buf;
			}
			else
			{ // 无需格式化
				std::cout << d.PrintfFormat;
			}
		})
	{
	}
}
